﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.Win32;
using Models;
using SuperQuery.UserControls;
using Views;

namespace SuperQuery
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, Views.IMainWindowView
    {
        public MainWindow()
        {
            InitializeComponent();

            // Set the DataContext so that data binding will work correctly
            DataContext = this;

            // Listen to when the SelectedQueryTab dependency property is changed and raise an event. This event
            // will enable us to switch to the tab that contains the query asigned to the SelectedQueryTab proeprty
            DependencyPropertyDescriptor selectedQueryDescr = DependencyPropertyDescriptor.
                FromProperty(SelectedQueryTabProperty, typeof(MainWindow));

            selectedQueryDescr.AddValueChanged(this, SelectedQueryTabChanged);

            // Set up the presenter
            m_Presenter = new Presenters.MainWindowPresenter(this);

            // Create a new query tab by default
            m_Presenter.NewQuery();
        }

        /// <summary>
        /// List of queries currently loaded
        /// </summary>
        public List<IQueryView> Queries
        {
            get;
            set;
        }

        /// <summary>
        /// The currently selected query
        /// </summary>
        public IQueryView SelectedQueryTab
        {
            get
            {
                return (IQueryView)GetValue(SelectedQueryTabProperty);
            }
            set
            {
                SetValue(SelectedQueryTabProperty, value);
            }
        }

        /// <summary>
        /// Provide access through the view to the currently loaded user configuration
        /// </summary>
        public UserConfiguration UserConfig
        {
            get;
            set;
        }

        /// <summary>
        /// Create a new query tab and return an instance of it's view
        /// </summary>
        /// <returns>A view that impliments IQuery</returns>
        public IQueryView NewQueryTab()
        {
            QueryTab newQueryTab = null;

            // Get the header template
            object closeableTabResouce = TryFindResource("ClosableTabItem");

            if ((closeableTabResouce != null) && (closeableTabResouce is DataTemplate))
            {
                // Create a new query tab control
                newQueryTab = new QueryTab(m_Presenter);

                // We found the header template so add the tab using it
                TabItem newTab = new TabItem
                                     {
                                         DataContext = newQueryTab,
                                         Content = newQueryTab,
                                         HeaderTemplate = (DataTemplate)closeableTabResouce,
                                     };

                // Bind the query name to the header text for this tab
                Binding headerBinding = new Binding("QueryName");
                BindingOperations.SetBinding(newTab, TabItem.HeaderProperty, headerBinding);

                tabQueries.Items.Add(newTab);

            }
            else
            {
                MessageBox.Show(
                    "Unable to create new query tab due to missing or corrupt resources. The EXE may be corrupt",
                    "Critical Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }

            // Return the newly created view or null if we could not create one
            return newQueryTab;
        }

        /// <summary>
        /// Close an existing query tab if possible
        /// </summary>
        /// <param name="queryTab">The query to close represented by it's view</param>
        public void CloseQueryTab(IQueryView queryTab)
        {
            // Find the tab whose content matches the supplied IQueryView
            TabItem tabToClose = ConvertQueryViewToTabItem(queryTab);

            if (tabToClose != null)
            {
                tabQueries.Items.Remove(tabToClose);
            }
        }

        /// <summary>
        /// Create a new query tab
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuNewQuery_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.NewQuery();
        }

        /// <summary>
        /// Open a new query tab and load a file in to it
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuOpenQupery_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.OpenQuery();
        }

        /// <summary>
        /// Save the currently displayed query under its current name
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuSaveQuery_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.SaveQuery(SelectedQueryTab, false /*Use existing query name if possible*/);
        }

        /// <summary>
        /// Save the currently displayed query under a certain file name
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuSaveQueryAs_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.SaveQuery(SelectedQueryTab, true /*Prompt the user for a new name*/);
        }

        /// <summary>
        /// Create a new database list
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuClearDatabaseList_Click(object sender, RoutedEventArgs e)
        {
            // Clean out the current list of databases
            m_Presenter.NewDatabaseList(SelectedQueryTab);
        }

        /// <summary>
        /// Open a database list and populate the database grid with its contents
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details of the event</param>
        private void mnuOpenDatabaseList_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.OpenDatabaseList(SelectedQueryTab);
        }

        /// <summary>
        /// Save a database list under it's current name
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details of the event</param>
        private void mnuSaveDatabaseList_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.SaveDatabaseList(SelectedQueryTab, false /*Use existing database list name if possible*/);
        }

        /// <summary>
        /// Save a database list under a new name
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuSaveDatabaseListAs_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.SaveDatabaseList(SelectedQueryTab, true /*Prompt the user for a new name, even if one already exists*/);
        }

        /// <summary>
        /// Close the main application window
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuQuit_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Load and display the help system
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuHelp_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.ShowHelp();
        }

        /// <summary>
        /// Show the about dialog
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuAbout_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.ShowAbout();
        }

        /// <summary>
        /// Close the selected tab
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void btnTabClose_Click(object sender, RoutedEventArgs e)
        {
            // For convenience the buttons Tag property is bound to the IQueryView we want to close
            Button closeButton = (Button)e.Source;
            if ((closeButton != null) && (closeButton.Tag is IQueryView))
            {
                IQueryView queryToClose = (IQueryView)closeButton.Tag;
                m_Presenter.CloseQuery(queryToClose);
            }
        }

        /// <summary>
        /// Take a query view and search the tab control for a tab that contains said query view
        /// </summary>
        /// <param name="queryView">The query view to search for</param>
        /// <returns>The tab item that contains the query view</returns>
        private TabItem ConvertQueryViewToTabItem(IQueryView queryView)
        {
            TabItem queryTabItem = null;

            if (queryView != null)
            {
                queryTabItem = (from TabItem item in tabQueries.Items
                                where item.Content.Equals(queryView)
                                select item).FirstOrDefault();
            }

            return queryTabItem;
        }

        /// <summary>
        /// Take a tab item and test to see if it contains a query view, if it does then return said query view 
        /// </summary>
        /// <param name="tabItem">The tab item that contains the query view</param>
        /// <returns>The query view contained within the tab item or null if the tab does not contain a query view</returns>
        private IQueryView ConvertTabItemToQueryView(TabItem tabItem)
        {
            IQueryView queryView = null;

            if ((tabItem != null) && (tabItem.Content is IQueryView))
            {
                queryView = (IQueryView)tabItem.Content;
            }

            return queryView;
        }

        /// <summary>
        /// The main window is being closed so we have to check to make sure no queries are running and prompt the
        /// user if they want to save any unsaved queries
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (!m_Presenter.CloseApplication())
            {
                // The close process failed for some reason. Either a query was stil running or the user cancelled a save
                // process. So we must stop the application shutting down
                e.Cancel = true;
            }
        }

        /// <summary>
        /// When the user changes the selected tab, update the SelectedQueryTab dependency propery
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void tabQueries_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (tabQueries.SelectedItem != null)
            {
                TabItem selectedTab = (TabItem)tabQueries.SelectedItem;
                SelectedQueryTab = (IQueryView)selectedTab.Content;
            }
            else
            {
                SelectedQueryTab = null;
            }
        }

        /// <summary>
        /// Select the tab item that contains the Query that has been assigned to the SelectedQueryTab dependency property
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void SelectedQueryTabChanged(object sender, EventArgs e)
        {
            TabItem tabToSelect = (from TabItem tab in tabQueries.Items
                                   where tab.Content.Equals(SelectedQueryTab)
                                   select tab).FirstOrDefault();

            if (tabToSelect != null)
            {
                tabQueries.SelectedItem = tabToSelect;
            }
        }

        /// <summary>
        /// The Export Database Result set menu option has been selected
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuExportResultSet_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.ExportResultSets(SelectedQueryTab);
        }

        /// <summary>
        /// Force the settings to be saved now
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void mnuSaveSettingsNow_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.SaveUserConfiguration();
        }

        /// <summary>
        /// The presenter for this window
        /// </summary>
        private readonly Presenters.MainWindowPresenter m_Presenter;

        /// <summary>
        /// Using a DependencyProperty as the backing store for SelectedQueryTab.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty SelectedQueryTabProperty =
            DependencyProperty.Register("SelectedQueryTab", typeof(IQueryView), typeof(MainWindow), new UIPropertyMetadata(null));
    }
}
